#region File Description
//-----------------------------------------------------------------------------
// SpinningTriangleControl.cs
//
// Microsoft XNA Community Game Platform
// Copyright (C) Microsoft Corporation. All rights reserved.
//-----------------------------------------------------------------------------
#endregion

#region Using Statements
using System.Diagnostics;
using System.Windows.Forms;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using SceneEngine;
using System.Collections.Generic;
using System;
#endregion

namespace SceneEditor
{
    /// <summary>
    /// Example control inherits from GraphicsDeviceControl, which allows it to
    /// render using a GraphicsDevice. This control shows how to draw animating
    /// 3D graphics inside a WinForms application. It hooks the Application.Idle
    /// event, using this to invalidate the control, which will cause the animation
    /// to constantly redraw.
    /// </summary>
    public class PreviewControl : ViewportControl
    {
        private Stopwatch timer;

        private string modelName;

        private Matrix[] bones;

        private Matrix projection;
        private Matrix view;

        public string ModelName
        {
            get { return modelName; }
            set 
            {
                modelName = value;

                if (string.IsNullOrEmpty(modelName) == false)
                {
                    Model model = EditorGlobals.ModelManager.Models[modelName];
                    BoundingSphere sphere = (model.Tag as ModelInformation).BoundingSphere;

                    this.bones = new Matrix[model.Bones.Count];
                    model.CopyAbsoluteBoneTransformsTo(bones);

                    view = Matrix.CreateLookAt(sphere.Center + Vector3.Normalize(Vector3.One) *
                        sphere.Radius * 3.5f, sphere.Center, Vector3.Up);
                }
            }
        }

        protected override void OnCreateControl()
        {
            float aspectRatio = (float)ClientSize.Width / (float)ClientSize.Height;

            projection = Matrix.CreatePerspectiveFieldOfView(
                MathHelper.PiOver4, aspectRatio, 0.1f, 10000.0f);

            timer = Stopwatch.StartNew();
        }

        /// <summary>
        /// Draws the control.
        /// </summary>
        public void Draw()
        {
            Viewport cachedViewport = EngineGlobals.GraphicsDevice.Viewport;

            EngineGlobals.GraphicsDevice.Viewport = new Viewport(
                0, 0, ClientSize.Width, ClientSize.Height);

            EngineGlobals.GraphicsDevice.Clear(Color.CornflowerBlue);
            EngineGlobals.GraphicsDevice.RasterizerState = RasterizerState.CullNone;

            if (string.IsNullOrEmpty(modelName) == false && 
                EditorGlobals.ModelManager.Models.ContainsKey(modelName))
            {
                float yaw = (float)timer.Elapsed.TotalSeconds * 0.7f;

                Model model = EditorGlobals.ModelManager.Models[modelName];

                foreach (ModelMesh mesh in model.Meshes)
                {
                    foreach (IEffectMatrices effect in mesh.Effects)
                    {
                        if (effect is AlphaTestEffect)
                        {
                            AlphaTestEffect alphaEffect = effect as AlphaTestEffect;

                            alphaEffect.AlphaFunction = CompareFunction.GreaterEqual;
                            alphaEffect.ReferenceAlpha = 200;
                        }

                        if (effect is BasicEffect)
                        {
                            (effect as BasicEffect).VertexColorEnabled = false;
                        }

                        effect.View = view;

                        effect.Projection = projection;

                        effect.World = bones[mesh.ParentBone.Index] * 
                            Matrix.CreateRotationY(yaw);
                    }

                    foreach (ModelMeshPart part in mesh.MeshParts)
                    {
                        if (part.NumVertices < 1)
                        {
                            continue;
                        }

                        EngineGlobals.GraphicsDevice.SetVertexBuffer(part.VertexBuffer, part.VertexOffset);
                        EngineGlobals.GraphicsDevice.Indices = part.IndexBuffer;

                        EffectTechnique technique = part.Effect.CurrentTechnique;
                        int passCount = technique.Passes.Count;

                        for (int passIndex = 0; passIndex < passCount; passIndex++)
                        {
                            technique.Passes[passIndex].Apply();

                            EngineGlobals.GraphicsDevice.DrawIndexedPrimitives(PrimitiveType.TriangleList,
                                                                 0,
                                                                 0,
                                                                 part.NumVertices,
                                                                 part.StartIndex,
                                                                 part.PrimitiveCount);
                        }
                    }
                }
            }

            Rectangle sourceRectangle = new Rectangle(0, 0, ClientSize.Width,
                                                            ClientSize.Height);

            EngineGlobals.GraphicsDevice.Present(sourceRectangle, null, Handle);

            EngineGlobals.GraphicsDevice.RasterizerState = RasterizerState.CullCounterClockwise;
            EngineGlobals.GraphicsDevice.Viewport = cachedViewport;
        }
    }
}
